package web.homework;

import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

class Order {
    private int userId;
    private List<OrderItem> orderItems = new ArrayList<>();
    private BigDecimal totalAmount;
    private String status;

    public Order() {}

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public void setOrderItems(List<OrderItem> orderItems) {
        this.orderItems = orderItems;
    }

    public void setTotalAmount(BigDecimal totalAmount) {
        this.totalAmount = totalAmount;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public int getUserId() {
        return userId;
    }

    public List<OrderItem> getOrderItems() {
        return orderItems;
    }

    public BigDecimal getTotalAmount() {
        return totalAmount;
    }

    public String getStatus() {
        return status;
    }
}

class OrderItem {
    private int productId;
    private int quantity;
    private BigDecimal price;

    public OrderItem() {}

    public void setProductId(int productId) {
        this.productId = productId;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public int getProductId() {
        return productId;
    }

    public int getQuantity() {
        return quantity;
    }

    public BigDecimal getPrice() {
        return price;
    }
}

@WebServlet("/api/place-order")
public class OrderServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 初始化响应内容类型
            response.setContentType("application/json");
            // 初始化响应状态码
            response.setStatus(HttpServletResponse.SC_OK);

            // 读取请求体中的JSON数据
            StringBuilder jsonStringBuilder = new StringBuilder();
            String line;
            try (BufferedReader reader = request.getReader()) {
                while ((line = reader.readLine()) != null) {
                    jsonStringBuilder.append(line);
                }
            } catch (IOException e) {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                response.getWriter().write("{\"success\": false, \"errorMessage\": \"Error reading request body.\"}");
                return;
            }

            String jsonString = jsonStringBuilder.toString();
            JSONObject jsonRequest = JSONObject.fromObject(jsonString);
            int userId = -1;
            JSONArray items = null;

            try {
                // 解析JSON数据
                userId = jsonRequest.getInt("userId");
                items = jsonRequest.getJSONArray("items");

                // 处理订单
                Order order = processOrder(userId, items);
                response.getWriter().write("{\"success\": true, \"orderId\": \"" + order.hashCode() + "\"}");
            } catch (JSONException e) {
                // 处理JSON解析错误
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                response.getWriter().write("{\"success\": false, \"errorMessage\": \"" + e.getMessage() + "\"}");
            } catch (Exception e) {
                // 处理其他异常
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                response.getWriter().write("{\"success\": false, \"errorMessage\": \"" + e.getMessage() + "\"}");
            }
        }


    private Order processOrder(int userId, JSONArray items) throws Exception {
        Order order = new Order();
        order.setUserId(userId);
        order.setStatus("PENDING");

        List<OrderItem> orderItems = new ArrayList<>();

        for (int i = 0; i < items.size(); i++) { // 使用 size() 代替 length
            JSONObject item = items.getJSONObject(i);
            int productId = item.getInt("productId");
            int quantity = item.getInt("quantity");

            if (!checkInventory(productId, quantity)) {
                throw new Exception("Inventory check failed for product ID: " + productId);
            }

            BigDecimal price = getProductPrice(productId);
            if (price == null) {
                throw new Exception("Product price not found for product ID: " + productId);
            }

            OrderItem orderItem = new OrderItem();
            orderItem.setProductId(productId);
            orderItem.setQuantity(quantity);
            orderItem.setPrice(price);

            orderItems.add(orderItem);
        }

        order.setOrderItems(orderItems);
        order.setTotalAmount(calculateTotal(orderItems));
        saveOrderToDatabase(order);

        return order;
    }

    private boolean checkInventory(int productId, int quantity) throws SQLException {
        Connection conn = DatabaseUtil.getConnection();
        String query = "SELECT StockQuantity FROM Products WHERE ProductID = ?";
        try (PreparedStatement pstmt = conn.prepareStatement(query)) {
            pstmt.setInt(1, productId);
            ResultSet rs = pstmt.executeQuery();
            if (rs.next()) {
                int stockQuantity = rs.getInt("StockQuantity");
                return stockQuantity >= quantity;
            }
        }
        return false;
    }

    private BigDecimal getProductPrice(int productId) throws SQLException {
        Connection conn = DatabaseUtil.getConnection();
        String query = "SELECT Price FROM Products WHERE ProductID = ?";
        try (PreparedStatement pstmt = conn.prepareStatement(query)) {
            pstmt.setInt(1, productId);
            ResultSet rs = pstmt.executeQuery();
            if (rs.next()) {
                return rs.getBigDecimal("Price");
            }
        }
        return null;
    }

    private BigDecimal calculateTotal(List<OrderItem> orderItems) {
        BigDecimal total = BigDecimal.ZERO;
        for (OrderItem item : orderItems) {
            total = total.add(item.getPrice().multiply(new BigDecimal(item.getQuantity())));
        }
        return total;
    }

    private void saveOrderToDatabase(Order order) throws SQLException {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            conn = DatabaseUtil.getConnection();
            conn.setAutoCommit(false);

            String insertOrderQuery = "INSERT INTO Orders (UserID, TotalAmount, Status) VALUES (?, ?, ?)";
            pstmt = conn.prepareStatement(insertOrderQuery, Statement.RETURN_GENERATED_KEYS);
            pstmt.setInt(1, order.getUserId());
            pstmt.setBigDecimal(2, order.getTotalAmount());
            pstmt.setString(3, order.getStatus());
            pstmt.executeUpdate();

            rs = pstmt.getGeneratedKeys();
            if (rs.next()) {
                int orderId = rs.getInt(1);
                for (OrderItem item : order.getOrderItems()) {
                    String insertOrderItemQuery = "INSERT INTO OrderItems (OrderID, ProductID, Quantity, Price) VALUES (?, ?, ?, ?)";
                    pstmt = conn.prepareStatement(insertOrderItemQuery);
                    pstmt.setInt(1, orderId);
                    pstmt.setInt(2, item.getProductId());
                    pstmt.setInt(3, item.getQuantity());
                    pstmt.setBigDecimal(4, item.getPrice());
                    pstmt.executeUpdate();
                }
            }

            conn.commit();
        } catch (SQLException e) {
            if (conn != null) {
                conn.rollback();
            }
            throw e;
        } finally {
            DatabaseUtil.close(conn, pstmt, rs);
        }
    }
}